/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.meta.controller.upgrade;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ZipUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.base.Strings;
import com.je.common.auth.impl.RealOrganizationUser;
import com.je.common.base.DynaBean;
import com.je.common.base.document.InternalFileBO;
import com.je.common.base.document.InternalFileUpload;
import com.je.common.base.mvc.AbstractPlatformController;
import com.je.common.base.mvc.BaseMethodArgument;
import com.je.common.base.result.BaseRespResult;
import com.je.common.base.service.CommonService;
import com.je.common.base.service.MetaService;
import com.je.common.base.service.rpc.DocumentInternalRpcService;
import com.je.common.base.upgrade.PackageResult;
import com.je.common.base.util.DateUtils;
import com.je.common.base.util.MessageUtils;
import com.je.common.base.util.SecurityUserHolder;
import com.je.common.base.util.StringUtil;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.meta.service.upgrade.UpgradeService;
import com.je.meta.util.enumUtil.UpgradeInstallStateEnum;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

@RestController
@RequestMapping(value = "/je/meta/upgrade")
public class UpgradeController extends AbstractPlatformController {

    @Autowired
    private MetaService metaService;
    @Autowired
    private UpgradeService upgradeService;
    @Autowired
    private Environment environment;
    @Autowired
    private DocumentInternalRpcService documentInternalRpcService;
    @Autowired
    private CommonService commonService;

    @RequestMapping(value = {"/getResourceIds"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult getResourceIds(BaseMethodArgument param, HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        String upgraderesourceType = getStringParameter(request, "type");
        return BaseRespResult.successResult(upgradeService.getResourceIds(upgradeId, upgraderesourceType));
    }

    @Override
    @RequestMapping(value = {"/doSave"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult doSave(BaseMethodArgument param, HttpServletRequest request) {
        String oldId = getStringParameter(request, "oldId");
        DynaBean dynaBean = manager.doSave(param, request);
        if (StringUtil.isNotEmpty(oldId)) {
            String result = upgradeService.saveResources(oldId, dynaBean.getStr("JE_META_UPGRADEPACKAGE_ID"));
        }
        return BaseRespResult.successResult(dynaBean.getValues());
    }

    @RequestMapping(value = {"/importDictionaryFromFuncinfo"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult importDictionaryFromFuncinfo(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }

        String result = upgradeService.importDictionaryFromFuncinfo(upgradeId);
        if (StringUtil.isNotEmpty(result)) {
            return BaseRespResult.errorResult(result);
        }
        return BaseRespResult.successResult("导入成功！");
    }

    @RequestMapping(value = {"/importTableByFuncinfo"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult importTableByFuncinfo(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }

        String result = upgradeService.importTableByFuncinfo(upgradeId);
        if (StringUtil.isNotEmpty(result)) {
            return BaseRespResult.errorResult(result);
        }
        return BaseRespResult.successResult("导入成功！");
    }

    @RequestMapping(value = {"/addPackageFuncs"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult addPackageFuncs(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        String funcIds = getStringParameter(request, "funcIds");
        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }

        if (Strings.isNullOrEmpty(funcIds)) {
            return BaseRespResult.errorResult("请选择要导入的功能！");
        }
        upgradeService.insertPackageFuncs(upgradeId, funcIds);
        return BaseRespResult.successResult("导入成功！");
    }

    @RequestMapping(value = {"/addPackageTables"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult addPackageTables(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        String tableIds = getStringParameter(request, "tableIds");
        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }

        if (Strings.isNullOrEmpty(tableIds)) {
            return BaseRespResult.errorResult("请选择要导入的表！");
        }

        upgradeService.insertPackageTables(upgradeId, tableIds);
        return BaseRespResult.successResult("导入成功！");
    }

    @RequestMapping(value = {"/addPackageDictionarys"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult addPackageDictionarys(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        String dictionaryIds = getStringParameter(request, "dictionaryIds");

        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }

        if (Strings.isNullOrEmpty(dictionaryIds)) {
            return BaseRespResult.errorResult("请选择要导入的字典！");
        }
        upgradeService.insertPackageDictionarys(upgradeId, dictionaryIds);
        return BaseRespResult.successResult("导入成功！");
    }

    @RequestMapping(value = {"/addPackageGlobalScripts"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult addPackageGlobalScripts(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        String scriptIds = getStringParameter(request, "scriptIds");

        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }

        if (Strings.isNullOrEmpty(scriptIds)) {
            return BaseRespResult.errorResult("请选择要导入的全局脚本！");
        }
        upgradeService.insertPackageGlobalScripts(upgradeId, scriptIds);
        return BaseRespResult.successResult("导入成功！");
    }

    @RequestMapping(value = {"/addPackageVariables"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult addPackageVariables(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        String variableIds = getStringParameter(request, "variableIds");

        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }
        if (Strings.isNullOrEmpty(variableIds)) {
            return BaseRespResult.errorResult("请选择要导入的系统变量！");
        }
        upgradeService.insertPackageSystemVariables(upgradeId, variableIds);
        return BaseRespResult.successResult("导入成功！");
    }

    @RequestMapping(value = {"/addPackageBusinessData"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult addPackageBusinessData(HttpServletRequest request) {
        String upgradeId = getStringParameter(request, "upgradeId");
        String tableIds = getStringParameter(request, "tableIds");

        if (Strings.isNullOrEmpty(upgradeId)) {
            return BaseRespResult.errorResult("请先构建升级包！");
        }
        if (Strings.isNullOrEmpty(tableIds)) {
            return BaseRespResult.errorResult("请选择要导入的资源表！");
        }
        upgradeService.insertPackageBusinessData(upgradeId, tableIds);
        return BaseRespResult.successResult("导入成功！");
    }

    /**
     * 打包
     */
    @ApiResponses({
            @ApiResponse(code = 200, response = File.class, message = ""),
    })
    @RequestMapping(value = "/doPackage", method = RequestMethod.GET, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResponseEntity<InputStream> doPackage(HttpServletRequest request) throws IOException {
        String upgradeId = getStringParameter(request, "upgradeId");
        if (Strings.isNullOrEmpty(upgradeId)) {
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_TYPE, "application/json")
                    .body(null);
        }
        DynaBean upgradeBean = metaService.selectOneByPk("JE_META_UPGRADEPACKAGE", upgradeId);
        if (upgradeBean == null) {
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_TYPE, "application/json")
                    .body(null);
        }
        upgradeBean.setStr("UPGRADEPACKAGE_PACKAGE_TIME", DateUtils.formatDateTime(new Date()));
        List<DynaBean> functionBeanList = metaService.select("JE_META_UPGRADERESOURCE", ConditionsWrapper.builder()
                .eq("JE_META_UPGRADEPACKAGE_ID", upgradeBean.getStr("JE_META_UPGRADEPACKAGE_ID")));
        List<String> funcIdList = new ArrayList<>();
        List<String> tableIdList = new ArrayList<>();
        List<String> dictionaryIdList = new ArrayList<>();
        List<String> globalScriptList = new ArrayList<>();
        List<String> variableList = new ArrayList<>();
        List<String> reportList = new ArrayList<>();
        List<String> chartList = new ArrayList<>();
        List<String> dataSourceList = new ArrayList<>();
        List<String> portalList = new ArrayList<>();
        Map<String, String> businessMap = new HashMap<>();

        List<String> roleIdList = new ArrayList<>();
        List<String> menuIdList = new ArrayList<>();
        List<String> topMenuIdList = new ArrayList<>();

        List<String> workflowIdList = new ArrayList<>();

        for (DynaBean eachResourceBean : functionBeanList) {
            if ("func".equals(eachResourceBean.getStr("UPGRADERESOURCE_TYPE_CODE"))) {
                funcIdList.add(eachResourceBean.getStr("UPGRADERESOURCE_CONTENT_CODE"));
            }
            if ("table".equals(eachResourceBean.getStr("UPGRADERESOURCE_TYPE_CODE"))) {
                tableIdList.add(eachResourceBean.getStr("UPGRADERESOURCE_CONTENT_CODE"));
            }
            if ("dictionary".equals(eachResourceBean.getStr("UPGRADERESOURCE_TYPE_CODE"))) {
                dictionaryIdList.add(eachResourceBean.getStr("UPGRADERESOURCE_CONTENT_CODE"));
            }
            if ("globalScript".equals(eachResourceBean.getStr("UPGRADERESOURCE_TYPE_CODE"))) {
                globalScriptList.add(eachResourceBean.getStr("UPGRADERESOURCE_CONTENT_CODE"));
            }
            if ("variable".equals(eachResourceBean.getStr("UPGRADERESOURCE_TYPE_CODE"))) {
                variableList.add(eachResourceBean.getStr("UPGRADERESOURCE_CONTENT_CODE"));
            }
            if ("report".equals(eachResourceBean.getStr("UPGRADERESOURCE_TYPE_CODE"))) {
                reportList.add(eachResourceBean.getStr("UPGRADERESOURCE_CONTENT_CODE"));
            }
            if ("chart".equals(eachResourceBean.getStr("UPGRADERESOURCE_TYPE_CODE"))) {
                chartList.add(eachResourceBean.getStr("UPGRADERESOURCE_CONTENT_CODE"));
            }
            if ("dataSource".equals(eachResourceBean.getStr("UPGRADERESOURCE_TYPE_CODE"))) {
                dataSourceList.add(eachResourceBean.getStr("UPGRADERESOURCE_CONTENT_CODE"));
            }
            if ("portal".equals(eachResourceBean.getStr("UPGRADERESOURCE_TYPE_CODE"))) {
                portalList.add(eachResourceBean.getStr("UPGRADERESOURCE_CONTENT_CODE"));
            }
            if ("role".equals(eachResourceBean.getStr("UPGRADERESOURCE_TYPE_CODE"))) {
                roleIdList.add(eachResourceBean.getStr("UPGRADERESOURCE_CONTENT_CODE"));
            }
            if ("topMenu".equals(eachResourceBean.getStr("UPGRADERESOURCE_TYPE_CODE"))) {
                topMenuIdList.add(eachResourceBean.getStr("UPGRADERESOURCE_CONTENT_CODE"));
            }
            if ("menu".equals(eachResourceBean.getStr("UPGRADERESOURCE_TYPE_CODE"))) {
                menuIdList.add(eachResourceBean.getStr("UPGRADERESOURCE_CONTENT_CODE"));
            }
            if ("workflow".equals(eachResourceBean.getStr("UPGRADERESOURCE_TYPE_CODE"))) {
                workflowIdList.add(eachResourceBean.getStr("UPGRADERESOURCE_CONTENT_CODE"));
            }
            if ("business".equals(eachResourceBean.getStr("UPGRADERESOURCE_TYPE_CODE"))) {
                String whereSql = eachResourceBean.getStr("UPGRADERESOURCE_CONTENT_VALUE");
                String tableId = eachResourceBean.getStr("UPGRADERESOURCE_CONTENT_CODE");
                DynaBean table = metaService.selectOneByPk("JE_CORE_RESOURCETABLE", tableId);
                businessMap.put(table.getStr("RESOURCETABLE_TABLECODE"), whereSql);
            }
        }

        upgradeBean.set("funcIdList", funcIdList);
        upgradeBean.set("tableIdList", tableIdList);
        upgradeBean.set("dictionaryIdList", dictionaryIdList);
        upgradeBean.set("globalScriptList", globalScriptList);
        upgradeBean.set("variableList", variableList);
        upgradeBean.set("reportList", reportList);
        upgradeBean.set("chartList", chartList);
        upgradeBean.set("dataSourceList", dataSourceList);
        upgradeBean.set("portalList", portalList);
        upgradeBean.set("roleIdList", roleIdList);
        upgradeBean.set("topMenuIdList", topMenuIdList);
        upgradeBean.set("menuIdList", menuIdList);
        upgradeBean.set("workflowIdList", workflowIdList);
        upgradeBean.set("businessMap", businessMap);
        PackageResult packageResult = upgradeService.doPackage(upgradeBean);
        InputStream zipInputStream = buildZip(packageResult);
        String tempDir = environment.getProperty("servicecomb.uploads.directory");
        if (!FileUtil.exist(tempDir)) {
            FileUtil.mkdir(tempDir);
        }

        String fileName = upgradeBean.getStr("UPGRADEPACKAGE_NAME") + ".zip";
        File zipFile = FileUtil.writeFromStream(zipInputStream, tempDir + File.separator + fileName);
        InternalFileUpload fileUpload = new InternalFileUpload(fileName, "application/zip", Long.valueOf(zipFile.length()));
        InternalFileBO fileBO = documentInternalRpcService.saveSingleFile(fileUpload, zipFile, SecurityUserHolder.getCurrentAccountId());

        JSONObject fileObj = new JSONObject();
        fileObj.put("name", fileName);
        fileObj.put("fileKey", fileBO.getFileKey());

        RealOrganizationUser realOrganizationUser = SecurityUserHolder.getCurrentAccount().getRealUser();
        DynaBean dynaBean = new DynaBean("JE_META_UPGRADEPACKAGE", false);
        dynaBean.setStr("UPGRADEPACKAGE_PACKAGE_FILE", fileObj.toJSONString());
        dynaBean.setStr("UPGRADEPACKAGE_PACKAGE_CODE", "1");
        dynaBean.setStr("UPGRADEPACKAGE_PACKAGE_TIME", DateUtils.formatDateTime(new Date()));
        dynaBean.setStr("UPGRADEPACKAGE_PACKAGEUSER_ID", realOrganizationUser.getId());
        dynaBean.setStr("UPGRADEPACKAGE_PACKAGEUSER_NAME", realOrganizationUser.getName());
        commonService.buildModelModifyInfo(dynaBean);
        metaService.update(dynaBean, ConditionsWrapper.builder().eq("JE_META_UPGRADEPACKAGE_ID", upgradeId));
        try {
            fileName = URLEncoder.encode(fileName, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            fileName = "未知文件.zip";
        }
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_TYPE, "application/zip")
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName)
                .body(FileUtil.getInputStream(zipFile));
    }

    /**
     * 上传升级包
     *
     * @return
     */
    @RequestMapping(value = "/uploadPackage", method = RequestMethod.POST, produces = "application/json; charset=utf-8", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public BaseRespResult uploadPackage(HttpServletRequest request) {
        DynaBean dynaBean = (DynaBean) request.getAttribute("dynaBean");
        upgradeService.doSave(dynaBean);
        return BaseRespResult.successResult("上传成功！");
    }


    /**
     * 安装前校验
     *
     * @return
     */
    @RequestMapping(value = {"/doCheck"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult doCheck(HttpServletRequest request) {
        String pkValue = getStringParameter(request, "pkValue");
        String result = upgradeService.doCheck(pkValue);
        if (StringUtil.isNotEmpty(result)) {
            return BaseRespResult.errorResult(result);
        }
        return BaseRespResult.successResult(MessageUtils.getMessage("common.operation.success"));
    }

    /**
     * 执行安装
     *
     * @return
     */
    @RequestMapping(value = {"/doInstall"}, method = RequestMethod.POST, produces = "application/json; charset=utf-8")
    public BaseRespResult doInstall(HttpServletRequest request) {
        String pkValue = getStringParameter(request, "pkValue");
        DynaBean dynaBean = metaService.selectOneByPk("JE_META_UPGRADEINSTALL", pkValue);
        String fileKey = dynaBean.getStr("UPGRADEINSTALL_FILE_KEY");
        if (Strings.isNullOrEmpty(fileKey)) {
            return BaseRespResult.errorResult(MessageUtils.getMessage("upgrade.fileKey.isNull"));
        }
        if (UpgradeInstallStateEnum.INSTALL.getValue().equals(dynaBean.getStr("UPGRADEINSTALL_INSTALL_CODE"))) {
            return BaseRespResult.errorResult(MessageUtils.getMessage("upgrade.already.install"));
        }
        upgradeService.doInstall(pkValue, fileKey);
        return BaseRespResult.successResult(MessageUtils.getMessage("common.upgrade.success"));
    }

    /**
     * 构建zip
     *
     * @param packageResult zip :
     *                      content.json
     *                      business.json
     *                      files/
     *                      file1
     *                      file2
     * @return
     */
    private InputStream buildZip(PackageResult packageResult) {
        String jsonString = JSON.toJSONString(packageResult);
        String tempDir = environment.getProperty("servicecomb.downloads.directory");
        File file = FileUtil.writeString(jsonString, tempDir + File.separator + "content.json", CharsetUtil.CHARSET_UTF_8);
        File zipFile = ZipUtil.zip(file, CharsetUtil.CHARSET_UTF_8);
        return FileUtil.getInputStream(zipFile);
    }

}
